//
// Created by tang on 23-3-11.
//

#ifndef PLUGIN_MGR_HPP
#define PLUGIN_MGR_HPP

#include "utils/singleton.hpp"
#include <plugin/plugin_interface.hpp>
#include <system/system.hpp>

#include <unordered_map>
#include <string>
#include <vector>
#include <memory>

class DynamicLibrary;

class PluginManager final: public PublicSingleton<PluginManager>
{
public:
    struct PluginLoader {
        PluginLoader(std::string fp);
        ~PluginLoader();

        std::string const  full_path;
        IPlugin           *plugin_inst;
        DynamicLibrary    *library;

        [[nodiscard]] inline bool is_loaded() const { return plugin_inst != nullptr; }
    private:
        bool try_load();
        bool active();
        bool deactivate();
        void shutdown();

        friend class PluginManager;
    };

    using LoaderPtr = std::shared_ptr<PluginLoader>;

    bool init();

    void clean();

    inline auto get_plugins() -> const std::unordered_map<std::string, LoaderPtr>&
    {
        return loadable_plugins;
    }

    void on_tick(f32 delta, f32 time);

private:
    bool active(std::string_view plugin_name);

    bool deactivate(std::string_view plugin_name);

    static std::vector<std::string> find_all_plugins(const std::vector<std::string> &paths);
    std::unordered_map<std::string, LoaderPtr> loadable_plugins;
};


#endif // PLUGIN_MGR_HPP
